#ifndef YHAIDA_BUFFER_H
#define YHAIDA_BUFFER_H
#include "../base/Utils.h"
#include "SocketsOps.h"
#include <algorithm>
#include <string>
#include <vector>

#include <assert.h>

#include <sys/uio.h>
namespace yhaida
{
    const char kCRLF[] = "\r\n";
    class Buffer
    {
    public:
        //相当于包头
        static const size_t kCheapPrepend = 8;
        //初始化buff的长度
        static const size_t kInitialSize = 1024;

    public:
        Buffer()
            : _buffer(kCheapPrepend + kInitialSize),
              _readIndex(kCheapPrepend),
              _writeIndex(_readIndex)
        {
            assert(prependableBytes() == kCheapPrepend);
            assert(readableBytes() == 0);
            assert(writableBytes() == kInitialSize);
        };
        ~Buffer() = default;
        //分三段
        //已读
        size_t prependableBytes() const { return _readIndex; }
        //可读（剩余）
        size_t readableBytes() const { return _writeIndex - _readIndex; }
        //可写（剩余）
        size_t writableBytes() const { return _buffer.size() - _writeIndex; }
        //返回vector中_readIndex位置的char指针
        const char *peek() const { return begin() + _readIndex; }
        int32_t peekInt32() const
        {
            assert(readableBytes() >= sizeof(int32_t));
            int32_t be32 = 0;
            ::memcpy(&be32, peek(), sizeof(be32));
            return sockets::networkToHost32(be32);
        }
        int8_t peekInt8() const
        {
            assert(readableBytes() >= sizeof(int8_t));
            int8_t x = *peek();
            return x;
        }
        char *beginWrite() { return begin() + _writeIndex; }

        const char *beginWrite() const { return begin() + _writeIndex; }
        void hasWritten(size_t len) { _writeIndex += len; }
        void unwrite(size_t len)
        {
            assert(len <= readableBytes());
            _writeIndex -= len;
        }

        // 首先这个里的swap是在class Buffer内部的方法，在class Buffer内部的方法里，当然可以访问Buffer的所有级别的变量，包括私有成员。
        void swap(Buffer &rhs)
        {
            _buffer.swap(rhs._buffer);
            std::swap(_readIndex, rhs._readIndex);
            std::swap(_writeIndex, rhs._writeIndex);
        }
        // find
        //回车
        const char *findCRLF() const
        {
            // FIXME: replace with memmem()?
            const char *crlf = std::search(peek(), beginWrite(), kCRLF, kCRLF + 2);
            return crlf == beginWrite() ? NULL : crlf;
        }

        const char *findCRLF(const char *start) const
        {
            assert(peek() <= start);
            assert(start <= beginWrite());
            // FIXME: replace with memmem()?
            const char *crlf = std::search(start, beginWrite(), kCRLF, kCRLF + 2);
            return crlf == beginWrite() ? NULL : crlf;
        }
        //终止
        const char *findEOL() const
        {
            const void *eol = memchr(peek(), '\n', readableBytes());
            return static_cast<const char *>(eol);
        }

        const char *findEOL(const char *start) const
        {
            assert(peek() <= start);
            assert(start <= beginWrite());
            const void *eol = memchr(start, '\n', beginWrite() - start);
            return static_cast<const char *>(eol);
        }

        //_readIndex自增
        void retrieve(size_t len)
        {
            assert(len <= readableBytes());
            _readIndex += len;
        }
        void retrieveUntil(const char *end)
        {
            assert(peek() <= end);
            assert(end <= beginWrite());
            retrieve(end - peek());
        }
        void retrieveAll()
        {
            // read追上write
            _readIndex = kCheapPrepend;
            _writeIndex = kCheapPrepend;
        }

        std::string retrieveAsString(size_t len)
        {
            assert(len <= readableBytes());
            std::string result(peek(), len);
            retrieve(len);
            return result;
        }

        std::string retrieveAllAsString()
        {
            return retrieveAsString(readableBytes());
        }

        //增加数据
        void ensureWritableBytes(size_t len)
        {
            if (writableBytes() < len)
            {
                makeSpace(len);
            }
            assert(writableBytes() >= len);
        }

        void append(const char *str, size_t len)
        {
            //先检查长度
            ensureWritableBytes(len);
            std::copy(str, str + len, beginWrite());
            hasWritten(len);
        }
        //注意(void*)
        void append(const void *str, size_t len)
        {
            append(static_cast<const char *>(str), len);
        }
        void append(const std::string &str)
        {
            append(str.data(), str.size());
        }

        void prepend(const void *str, size_t len)
        {
            assert(len <= prependableBytes());
            _readIndex -= len;
            const char *d = static_cast<const char *>(str);
            std::copy(d, d + len, begin() + _readIndex);
        }
        void prependInt32(int32_t x)
        {
            int32_t be32 = sockets::hostToNetwork32(x);
            prepend(&be32, sizeof(be32));
        }
        void appendInt32(int32_t x)
        {
            int32_t be32 = sockets::hostToNetwork32(x);
            append(&be32, sizeof(be32));
        }

        void shrink(size_t reserve)
        {
            std::vector<char> buff(kCheapPrepend + readableBytes() + reserve);
            std::copy(peek(), peek() + readableBytes(), buff.begin() + kCheapPrepend);
            buff.swap(_buffer);
        }

        int32_t readInt32()
        {
            int32_t result = peekInt32();
            retrieve(sizeof(int32_t));
            return result;
        }

        int8_t readInt8()
        {
            int8_t result = peekInt8();
            retrieve(sizeof(int8_t));
            return result;
        }

        //核心
        ssize_t readFD(int fd, int *savedErrno)
        {
            // 散布读（scatter read）和聚集写（gather write）。
            char extrabuff[65536];
            struct iovec vec[2];
            const size_t writable = writableBytes();
            vec[0].iov_base = begin() + _writeIndex;
            vec[0].iov_len = writable;
            vec[1].iov_base = extrabuff;
            vec[1].iov_len = sizeof(extrabuff);

            const ssize_t n = readv(fd, vec, 2);
            if (n < 0)
            {
                *savedErrno = errno;
            }
            else if (Utils::implicit_cast<size_t>(n) <= writable)
            {
                _writeIndex += n;
            }
            else
            {
                _writeIndex = _buffer.size();
                append(extrabuff, n - writable);
            }
            return n;
        }

    private:
        char *begin() { return &*_buffer.begin(); }
        const char *begin() const { return &*_buffer.begin(); }
        //内部腾挪->核心
        void makeSpace(size_t len)
        {
            if (writableBytes() + prependableBytes() < len + kCheapPrepend)
            {
                //内部空间不够了
                _buffer.resize(_writeIndex + len);
            }
            else
            {
                assert(kCheapPrepend < _readIndex);
                size_t readable = readableBytes();
                std::copy(begin() + _readIndex, begin() + _writeIndex, begin() + kCheapPrepend);
                _readIndex = kCheapPrepend;
                _writeIndex = _readIndex + readable;
                assert(readable == readableBytes());
            }
        }

    private:
        // +-------------------+------------------+------------------+
        // | prependable bytes |  readable bytes  |  writable bytes  |
        // |                   |     (CONTENT)    |                  |
        // +-------------------+------------------+------------------+
        // |                   |                  |                  |
        // 0      <=      readerIndex   <=   writerIndex    <=     size
        std::vector<char> _buffer;
        size_t _readIndex;
        size_t _writeIndex;
    };
}
#endif